﻿//========================================================= 
/**@file DevHelperForWin32.h 
 * @brief Windows下一些设备操作辅助类 
 * 
 * @date 2012-04-04   11:09:35 
 * @author Zhyioo 
 * @version 1.0
 */ 
//--------------------------------------------------------- 
#ifndef _LIBZHOUYB_DEVHELPERFORWIN32_H_
#define _LIBZHOUYB_DEVHELPERFORWIN32_H_
//--------------------------------------------------------- 
#include "DevHelper.h"
//--------------------------------------------------------- 
namespace zhou_yb {
namespace extension {
namespace ability {
//--------------------------------------------------------- 
//--------------------------------------------------------- 
// 是否包含串口的头文件目录 
#ifndef NO_INCLUDE_COM_SOURCE
/// 串口辅助类 
class ComDeviceHelper
{
protected:
    ComDeviceHelper() {}
public:
    /**
     * @brief 打开串口 
     * 
     * @param [in] dev 需要操作的设备 
     * @param [in] port 需要打开的串口号
     * @param [in] baud 打开串口的波特率 
     */
    template<class TComDevice>
    static DevHelper::ErrEnum OpenDevice(TComDevice& dev, uint port, uint baud = CBR_9600)
    {
        LOG_OBJ_INIT(dev);
        LOG_FUNC_NAME();
        LOGGER(_log << "串口号:<" << port << ">,波特率:<" << baud << ">\n");

        if(dev.Open(port))
        {
            dev.SetProperty(baud);
            dev.SetComTimeout(DEV_OPERATOR_INTERVAL, 0, 0);
            return DevHelper::EnumSUCCESS;
        }

        return DevHelper::EnumFAILE;
    }
};
#endif
//--------------------------------------------------------- 
// 是否包含Socket头文件目录 
#ifdef INCLUDE_BTH_SOURCE
/// 蓝牙设备辅助类 
class BluetoothDeviceHelper
{
protected:
    BluetoothDeviceHelper() {}
public:
    /**
     * @brief 打开指定名称的蓝牙设备 
     * 
     * @param [in] dev 需要操作的设备 
     * @param [in] devName 需要连接的设备名称
     * @param [in] devPwd [default:NULL] 蓝牙配对的PIN码 
     * @param [in] devUUID [default:NULL] 连接蓝牙的UUID
     * @param [in] devPort [default:BT_PORT_ANY] 蓝牙端口号
     * @param [in] isOnlyPaired [default:true] 是否只查找已经配对的设备
     * @param [out] pFullName [default:NULL] 连接设备时的完整名称
     */
    template<class TBluetoothDevice>
    static DevHelper::ErrEnum OpenDevice(TBluetoothDevice& dev, const char* devName, 
        const char* devPwd = NULL, const char* devUUID = NULL, uint devPort = BT_PORT_ANY, 
        bool isOnlyPaired = true, ByteBuilder* pFullName = NULL)
    {
        LOG_OBJ_INIT(dev);
        LOG_FUNC_NAME();
        LOGGER(_log << "Name:<" << _strput(devName) << ">\n"
            << "Pin:<" << _strput(devPwd) << ">\n"
            << "UUID:<" << _strput(devUUID) << ">\n"
            << "Port:<" << devPort << ">\n");

        // 枚举所有的远程设备 
        list_t<typename TBluetoothDevice::device_info> devlist;
        BLUETOOTH_DEVICE_SEARCH_PARAMS  bdsp;
        ZeroMemory(&bdsp, sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS));
        bdsp.dwSize = sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS);
        bdsp.hRadio = NULL;
        bdsp.fReturnAuthenticated = TRUE;
        bdsp.fReturnRemembered = TRUE;
        bdsp.fReturnUnknown = TRUE;
        bdsp.fReturnConnected = TRUE;
        bdsp.fIssueInquiry = FALSE;
        bdsp.cTimeoutMultiplier = 0x01;
        // 没有枚举到设备 
        if(dev.EnumRemoteDevice(devlist, NULL, &bdsp) < 1)
        {
            LOGGER(_log.WriteLine("没有枚举到远程蓝牙设备"));
            return DevHelper::EnumERROR;
        }
        typedef typename list_t<typename TBluetoothDevice::device_info>::iterator Iterator;

        Iterator bthitr;
        list_t<Iterator> pairlist;
        list_t<Iterator> scanlist;
        ByteArray scanName(devName);
        size_t bthCount = 0;
        for(bthitr = devlist.begin();bthitr != devlist.end(); ++bthitr)
        {
            ByteArray btName(bthitr->Name.c_str(), bthitr->Name.length());
            if(StringConvert::Contains(btName, scanName, true))
            {
                ++bthCount;
                if(bthitr->IsAuthenticated)
                {
                    pairlist.push_back(bthitr);
                }
                else
                {
                    if(!isOnlyPaired)
                    {
                        scanlist.push_back(bthitr);
                    }
                }
            }
        }

        if(bthCount < 1)
        {
            LOGGER(_log.WriteLine("没有找到匹配指定名称的蓝牙设备"));
            return DevHelper::EnumERROR;
        }
        // 优先连接已配对的设备
        typename list_t<Iterator>::iterator itr;
        for(itr = pairlist.begin();itr != pairlist.end(); ++itr)
        {
            if(dev.Open(NULL, (*itr)->Address, devPwd, devUUID, devPort))
            {
                if(pFullName != NULL)
                {
                    pFullName->Append((*itr)->Name.c_str());
                }
                LOGGER(_log.WriteLine("打开已配对蓝牙设备成功"));
                return DevHelper::EnumSUCCESS;
            }
        }
        // 连接未配对的设备
        for(itr = scanlist.begin();itr != scanlist.end(); ++itr)
        {
            if(dev.Open(NULL, (*itr)->Address, devPwd, devUUID, devPort))
            {
                if(pFullName != NULL)
                {
                    pFullName->Append((*itr)->Name.c_str());
                }
                LOGGER(_log.WriteLine("打开未配对蓝牙设备成功"));
                return DevHelper::EnumSUCCESS;
            }
        }
        LOGGER(_log.WriteLine("打开蓝牙设备失败"));
        return DevHelper::EnumFAILE;
    }
    /**
     * @brief 根据指定的地址打开蓝牙设备
     * @date 2016-10-31 22:13
     * 
     * @param [in] dev 需要操作的设备
     * @param [in] sAdr 需要连接的蓝牙地址
     * @param [in] devPwd [default:NULL] 蓝牙的配对密码
     * @param [in] devUUID [default:NULL] 连接蓝牙的UUID
     * @param [in] devPort [default:BT_PORT_ANY] 蓝牙端口号
     */
    template<class TBluetoothDevice>
    static DevHelper::ErrEnum OpenWithAddress(TBluetoothDevice& dev, const char* sAdr, const char* devPwd = NULL, const char* devUUID = NULL, uint devPort = BT_PORT_ANY)
    {
        LOG_OBJ_INIT(dev);
        LOG_FUNC_NAME();
        LOGGER(_log << "Address:<" << _strput(sAdr) << ">\n"
            << "Pin:<" << _strput(devPwd) << ">\n"
            << "UUID:<" << _strput(devUUID) << ">\n"
            << "Port:<" << devPort << ">\n");

        BLUETOOTH_DEVICE_SEARCH_PARAMS  bdsp;
        ZeroMemory(&bdsp, sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS));
        bdsp.dwSize = sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS);
        bdsp.hRadio = NULL;
        bdsp.fReturnAuthenticated = TRUE;
        bdsp.fReturnRemembered = TRUE;
        bdsp.fReturnUnknown = TRUE;
        bdsp.fReturnConnected = TRUE;
        bdsp.fIssueInquiry = FALSE;
        bdsp.cTimeoutMultiplier = 0x01;
        // 枚举所有的远程设备 
        list_t<typename TBluetoothDevice::device_info> devlist;
        // 没有枚举到设备 
        if(dev.EnumRemoteDevice(devlist, NULL, &bdsp) < 1)
        {
            LOGGER(_log.WriteLine("没有枚举到远程蓝牙设备"));
            return DevHelper::EnumERROR;
        }

        typename list_t<typename TBluetoothDevice::device_info>::iterator itr;
        BTH_ADDR adr = TBluetoothDevice::StringToAddress(sAdr);
        for(itr = devlist.begin();itr != devlist.end(); ++itr)
        {
            if(itr->Address == adr)
                break;
        }

        if(itr == devlist.end())
        {
            LOGGER(_log.WriteLine("没有找到匹配指定地址的蓝牙设备"));
            return DevHelper::EnumERROR;;
        }
        if(dev.Open(NULL, itr->Address, devPwd, devUUID, devPort))
        {
            LOGGER(_log.WriteLine("打开设备成功"));
            return DevHelper::EnumSUCCESS;
        }
        LOGGER(_log.WriteLine("打开设备失败"));
        return DevHelper::EnumFAILE;
    }
    /**
     * @brief 根据名称查找第一个匹配的设备蓝牙地址
     * @date 2017-01-21 16:22
     * 
     * @param [in] dev 需要操作的设备
     * @param [in] devName 需要获取地址的设备名称
     * @param [out] bthAdr 获取到的地址
     */
    template<class TBluetoothDevice>
    static DevHelper::ErrEnum ScanAddressByName(TBluetoothDevice& dev, const char* devName, BTH_ADDR& bthAdr, HANDLE& hLocalRadio)
    {
        LOG_OBJ_INIT(dev);
        LOG_FUNC_NAME();
        LOGGER(_log << "Name:<" << _strput(devName) << ">\n");

        // 枚举本地蓝牙 
        list_t<typename TBluetoothDevice::device_info> localdevlist;
        if(dev.EnumLocalDevice(localdevlist, true) < 1)
        {
            LOGGER(_log.WriteLine("没有枚举到本地蓝牙设备"));
            return DevHelper::EnumERROR;
        }
        // 枚举所有的远程设备 
        list_t<typename TBluetoothDevice::device_info> devlist;
        BLUETOOTH_DEVICE_SEARCH_PARAMS  bdsp;
        ZeroMemory(&bdsp, sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS));
        bdsp.dwSize = sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS);
        bdsp.hRadio = NULL;
        bdsp.fReturnAuthenticated = TRUE;
        bdsp.fReturnRemembered = TRUE;
        bdsp.fReturnUnknown = TRUE;
        bdsp.fReturnConnected = TRUE;
        bdsp.fIssueInquiry = FALSE;
        bdsp.cTimeoutMultiplier = 0x01;
        // 没有枚举到设备 
        if(dev.EnumRemoteDevice(devlist, NULL, &bdsp) < 1)
        {
            LOGGER(_log.WriteLine("没有枚举到远程蓝牙设备"));
            return DevHelper::EnumERROR;
        }

        typename list_t<typename TBluetoothDevice::device_info>::iterator itr;
        ByteArray scanName(devName);
        for(itr = devlist.begin();itr != devlist.end(); ++itr)
        {
            ByteArray btName(itr->Name.c_str(), itr->Name.length());
            if(StringConvert::Contains(btName, scanName, true))
                break;
        }

        if(itr == devlist.end())
        {
            LOGGER(_log.WriteLine("没有找到匹配指定名称的蓝牙设备"));
            return DevHelper::EnumERROR;
        }

        bthAdr = itr->Address;
        hLocalRadio = localdevlist.front().hRadio;
        return DevHelper::EnumSUCCESS;
    }
};
#endif
//--------------------------------------------------------- 
// 是否包含DDK的头文件目录 
#ifndef NO_INCLUDE_USB_SOURCE
/// HID设备辅助类 
class HidDeviceHelper
{
protected:
    HidDeviceHelper() {}
public:
    /**
     * @brief 打开指定VID,PID,版本号的HID设备
     * @param [in] dev 需要代理操作的设备
     * @param [in] vid 设备的VID 
     * @param [in] pid 设备的PID 
     * @param [in] index [default:SIZE_EOF] 连接多个设备时的索引号,如果超过pList范围则依次查找直到成功为止
     * @param [in] pList [default:NULL] 设备列表,如果为NULL则自动重新枚举
     * @param [in] isReadOnly [default:false] 是否是只读的设备
     */
    template<class THidDevice>
    static DevHelper::ErrEnum OpenDevice(THidDevice& dev, ushort vid, ushort pid,
        size_t index = SIZE_EOF, list_t<HidDevice::device_info>* pList = NULL, bool isReadOnly = false)
    {
        LOG_OBJ_INIT(dev);
        LOG_FUNC_NAME();
        LOGGER(_log<<"VID:<"<<_hex(vid)<<">,PID:<"<<_hex(pid)<<">\n");

        list_t<HidDevice::device_info> devlist;
        if(pList == NULL)
        {
            dev.EnumDevice(devlist, false);
            pList = &devlist;
        }

        DevHelper::ErrEnum rlt = DevHelper::EnumERROR;
        size_t count = 0;
        size_t devCount = pList->size();
        list_t<HidDevice::device_info>::iterator itr;

        for(itr = pList->begin();itr != pList->end(); ++itr)
        {
            if((itr->Vid == vid) && (itr->Pid == pid))
            {
                LOGGER(_log << "找到匹配VID[" << _hex(vid)
                    << "],PID[" << _hex(pid) << "]的设备,索引:<" << count << ">\n");
                if(count == index || index >= devCount)
                {
                    bool bOpen = false;
                    if (isReadOnly)
                    {
                        string devArg = FileHandlerFactory::ToArg(itr->Path.c_str(), OPEN_EXISTING, TRUE);
                        bOpen = dev.Open(devArg.c_str());
                    }
                    else
                    {
                        bOpen = dev.Open(itr->Path.c_str());
                    }
                    if(bOpen)
                    {
                        rlt = DevHelper::EnumSUCCESS;
                        break;
                    }
                    else
                    {
                        rlt = DevHelper::EnumFAILE;
                    }
                    if(count == index)
                        break;
                }

                ++count;
            }
        }
        // 在列表中没有找到指定的设备
        LOGGER(if(itr == pList->end())
        {
            if(rlt == DevHelper::EnumERROR)
                _log << "没有找到VID[" << _hex(vid) << "],PID[" << _hex(pid) << "]的设备" << endl;
            else
                _log.WriteLine("打开设备失败");
        });

        return rlt;
    }
    /**
     * @brief 打开指定名词的设备
     * @param [in] dev 需要代理操作的设备
     * @param [in] devName 设备名称(部分名称或全名)
     * @param [in] index [default:SIZE_EOF] 连接多个设备时的索引号,如果超过pList范围则依次查找直到成功为止
     * @param [in] pList [default:NULL] 设备列表,如果为NULL则自动重新枚举 
     */
    template<class THidDevice>
    static DevHelper::ErrEnum OpenDevice(THidDevice& dev, const char* devName, size_t index = SIZE_EOF,
        list_t<HidDevice::device_info>* pList = NULL)
    {
        LOG_OBJ_INIT(dev);
        LOG_FUNC_NAME();
        LOGGER(_log<<"devName:<"<<_strput(devName)<<">\n");

        list_t<THidDevice::device_info> _list;
        if(pList == NULL)
        {
            dev.EnumDevice(_list);
            pList = &_list;
        }
        size_t devCount = pList->size();
        size_t count = 0;
        DevHelper::ErrEnum rlt = DevHelper::EnumERROR;
        typename list_t<THidDevice::device_info>::iterator itr;
        if(_is_empty_or_null(devName))
        {
            itr = pList->begin();
        }
        else
        {
            for(itr = pList->begin();itr != pList->end(); ++itr)
            {
                if(StringConvert::Contains(itr->Name.c_str(), devName, true))
                {
                    LOGGER(_log << "找到匹配[" << _strput(devName) << "]的设备<" << (itr->Name) << ">,索引:<" << count << ">\n");
                    if(index == count || index >= devCount)
                    {
                        if(dev.Open(itr->Path.c_str()))
                        {
                            rlt = DevHelper::EnumSUCCESS;
                            break;
                        }
                        else
                        {
                            rlt = DevHelper::EnumFAILE;
                        }
                        if(count == index)
                            break;
                    }

                    ++count;
                }
            }
        }
        // 在列表中没有找到指定的设备 
        if(itr == pList->end())
        {
            LOGGER(_log<<"没有找到类似名称["<<_strput(devName)<<"]的设备"<<endl);
            return DevHelper::EnumERROR;
        }

        return rlt;
    }
    /// 返回是否存在指定名称的设备 
    static DevHelper::ErrEnum IsExist(const char* devName, list_t<HidDevice::device_info>* pList = NULL)
    {
        HidDevice dev;
        list_t<HidDevice::device_info> _list;
        list_t<HidDevice::device_info>::iterator itr;

        if(pList == NULL)
        {
            dev.EnumDevice(_list);
            pList = &_list;
        }
        for(itr = pList->begin();itr != pList->end(); ++itr)
        {
            if(StringConvert::Contains(itr->Name.c_str(), devName, true))
                return DevHelper::EnumSUCCESS;
        }
        return DevHelper::EnumERROR;
    }
    /// 返回是否存在指定VID,PID的设备 
    static DevHelper::ErrEnum IsExist(ushort vid, ushort pid, list_t<HidDevice::device_info>* pList = NULL)
    {
        HidDevice dev;
        list_t<HidDevice::device_info> _list;
        list_t<HidDevice::device_info>::iterator itr;

        if(pList == NULL)
        {
            dev.EnumDevice(_list);
            pList = &_list;
        }

        for(itr = pList->begin();itr != pList->end(); ++itr)
        {
            if(itr->Vid == vid && itr->Pid == pid)
                return DevHelper::EnumSUCCESS;
        }
        return DevHelper::EnumERROR;
    }
};
#endif // ! NO_INCLUDE_USB_SOURCE
//--------------------------------------------------------- 
#ifdef INCLUDE_SOCKET_SOURCE
class SocketDeviceHelper
{
protected:
    SocketDeviceHelper() {}
public:
    /**
     * @brief 连接指定的IP地址
     * @date 2018-12-07 14:29
     */
    template<class TSocketDevice>
    static DevHelper::ErrEnum Connect(TSocketDevice& dev, const char* ip, ushort port)
    {
        string socketArg = SocketHandlerFactory::ToArg(AF_INET, SOCK_STREAM, 0);
        if(!dev.Open(socketArg.c_str()))
            return DevHelper::EnumERROR;
        SOCKADDR_IN addr;
        addr.sin_family = AF_INET;
        addr.sin_port = htons(port);
        addr.sin_addr.S_un.S_addr = inet_addr(ip);
        return DevHelper::ToHelperResult(dev.Connect(reinterpret_cast<sockaddr*>(&addr), sizeof(SOCKADDR_IN)));
    }
};
#endif
//--------------------------------------------------------- 
} // namespace ability 
} // namespace extension 
} // namespace zhou_yb
//--------------------------------------------------------- 
#endif // _LIBZHOUYB_DEVHELPERFORWIN32_H_
//========================================================= 
